package com.linln.common.utils;

import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.Random;

/**
 * @author : pengliang
 * @version V1.0
 * @Project: timo
 * @Package com.linln.common.utils
 * @Descriptio /**
 * @Project: timo
 * @Package com.linln.common.utils
 * @Description: 生成去拿吗
 * @date Date : 2020年11月24日 9:55
 */
public class CodeUtil {
    static String stringtable = "abcdefghijkmnpqrstuvwxyz23456789";
    final static String password = "dak3le2"; //密码

    //从byte转为字符表索引所需要的位数
    final static int convertByteCount = 5;

    public static void main(String[] args) throws Exception {
        ShowTime();
        System.out.println("=======================");
        System.out.println(createOne());
        System.out.println(createOne());
        System.out.println(createOne());
        System.out.println(createOne());

    }

    //生成一条券码
    public static String createOne() {
        int length = 12;
        String val = "";
        Random random = new Random();
        //length为几位密码
        for(int i = 0; i < length; i++) {
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //输出字母还是数字
            if( "char".equalsIgnoreCase(charOrNum) ) {
                //输出是大写字母还是小写字母
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char)(random.nextInt(26) + temp);
            } else if( "num".equalsIgnoreCase(charOrNum) ) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }

    //转换格式 将************ 为 ****-****-****
    public static String trans(String code) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < code.length(); i++) {
            if (i != 0 && i % 4 == 0) {
                sb.append("-");
            }
            sb.append(code.charAt(i));
        }
        return sb.toString();
    }

    //还原格式 将****-****-**** 为 ************
    public static String reduction(String code) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < code.length(); i++) {
            char c = code.charAt(i);
            if (c != '-') {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 生成兑换码
     * 这里每一次生成兑换码的最大数量为int的最大值即2147483647
     *
     * @return
     */
    public static String[] create(byte groupid, int codecount, int codelength, String password) {
        //8位的数据总长度
        int fullcodelength = codelength * convertByteCount / 8;
        //随机码对时间和id同时做异或处理
        //类型1，id4，随机码n,校验码1
        int randcount = fullcodelength - 6;//随机码有多少个
        //保存生成的随机码
        String[] resultCode = new String[codecount];
        //如果随机码小于0 不生成
        if (randcount <= 0) {
            return null;
        }
        for (int i = 0; i < codecount; i++) {
            //这里使用i作为code的id
            //生成n位随机码
            byte[] randbytes = new byte[randcount];
            for (int j = 0; j < randcount; j++) {
                randbytes[j] = (byte) (Math.random() * Byte.MAX_VALUE);
            }

            //存储所有数据
            ByteHapper byteHapper = ByteHapper.CreateBytes(fullcodelength);
            byteHapper.AppendNumber(groupid).AppendNumber(i).AppendBytes(randbytes);

            //计算校验码 这里使用所有数据相加的总和与byte.max 取余
            byte verify = (byte) (byteHapper.GetSum() % Byte.MAX_VALUE);
            byteHapper.AppendNumber(verify);

            //使用随机码与时间和ID进行异或
            for (int j = 0; j < 5; j++) {
                byteHapper.bytes[j] = (byte) (byteHapper.bytes[j] ^ (byteHapper.bytes[5 + j % randcount]));
            }

            //使用密码与所有数据进行异或来加密数据
            byte[] passwordbytes = password.getBytes();
            for (int j = 0; j < byteHapper.bytes.length; j++) {
                byteHapper.bytes[j] = (byte) (byteHapper.bytes[j] ^ passwordbytes[j % passwordbytes.length]);
            }

            //这里存储最终的数据
            byte[] bytes = new byte[codelength];

            //按6位一组复制给最终数组
            for (int j = 0; j < byteHapper.bytes.length; j++) {
                for (int k = 0; k < 8; k++) {
                    int sourceindex = j * 8 + k;
                    int targetindex_x = sourceindex / convertByteCount;
                    int targetindex_y = sourceindex % convertByteCount;
                    byte placeval = (byte) Math.pow(2, k);
                    byte val = (byte) ((byteHapper.bytes[j] & placeval) == placeval ? 1 : 0);
                    //复制每一个bit
                    bytes[targetindex_x] = (byte) (bytes[targetindex_x] | (val << targetindex_y));
                }
            }

            StringBuilder result = new StringBuilder();
            //编辑最终数组生成字符串
            for (int j = 0; j < bytes.length; j++) {
                result.append(stringtable.charAt(bytes[j]));
            }
            resultCode[i] = result.toString();
        }
        ShowTime();
        return resultCode;
    }

    /**
     * 验证兑换码
     *
     * @param code
     */
    public static boolean VerifyCode(String code) {
        byte[] bytes = new byte[code.length()];

        //首先遍历字符串从字符表中获取相应的二进制数据
        for (int i = 0; i < code.length(); i++) {
            byte index = (byte) stringtable.indexOf(code.charAt(i));
            bytes[i] = index;
        }

        //还原数组
        int fullcodelength = code.length() * convertByteCount / 8;
        int randcount = fullcodelength - 6;//随机码有多少个

        byte[] fullbytes = new byte[fullcodelength];
        for (int j = 0; j < fullbytes.length; j++) {
            for (int k = 0; k < 8; k++) {
                int sourceindex = j * 8 + k;
                int targetindex_x = sourceindex / convertByteCount;
                int targetindex_y = sourceindex % convertByteCount;

                byte placeval = (byte) Math.pow(2, targetindex_y);
                byte val = (byte) ((bytes[targetindex_x] & placeval) == placeval ? 1 : 0);

                fullbytes[j] = (byte) (fullbytes[j] | (val << k));
            }
        }

        //解密，使用密码与所有数据进行异或来加密数据
        byte[] passwordbytes = password.getBytes();
        for (int j = 0; j < fullbytes.length; j++) {
            fullbytes[j] = (byte) (fullbytes[j] ^ passwordbytes[j % passwordbytes.length]);
        }

        //使用随机码与时间和ID进行异或
        for (int j = 0; j < 5; j++) {
            fullbytes[j] = (byte) (fullbytes[j] ^ (fullbytes[5 + j % randcount]));
        }

        //获取校验码 计算除校验码位以外所有位的总和
        int sum = 0;
        for (int i = 0; i < fullbytes.length - 1; i++) {
            sum += fullbytes[i];
        }
        byte verify = (byte) (sum % Byte.MAX_VALUE);

        //校验
        if (verify == fullbytes[fullbytes.length - 1]) {
            System.out.println(code + " : verify success!");
            return true;
        } else {
            System.out.println(code + " : verify failed!");
            return false;
        }


    }

    /**
     * @Description: 获取String类型16流水号
     * @return  String类型16流水号
     * @date 2017年07月20日 下午03:55:21
     */
    public static String getTimeSerialNoStr(){
        StringBuilder serialNo=new StringBuilder();
        Random r = new Random();
        Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR)-2000;
        int month = c.get(Calendar.MONTH) + 1;
        int day = c.get(Calendar.DAY_OF_MONTH);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
        int ms = c.get(Calendar.MILLISECOND);
        serialNo.append(year).append(month).append(day)
                .append(hour).append(minute).append(second)
                .append(ms).append(r.nextInt(1000));
        return serialNo.toString();
    }

    public static void ShowTime() {
        Date date = new Date();
        long times = date.getTime();//时间戳
        System.out.println("time  : " + times);
    }

}
